﻿using K3Cloud.WebApi.Core.IoC.Types;
using SQLBuilder.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

namespace K3Cloud.WebApi.Core.IoC.K3Client
{
    /// <summary>
    /// IK3Queryable 定义K3Cloud表单查询的链式操作接口。
    /// 支持Where筛选、OrderBy排序、分页、缓存、聚合等操作。
    /// </summary>
    /// <typeparam name="T">表单实体类型</typeparam>
    public partial interface IK3Queryable<T>
    {
        /// <summary>
        /// 添加筛选条件。
        /// </summary>
        /// <param name="expression">Lambda表达式筛选条件</param>
        /// <returns>链式调用接口</returns>
        IK3Queryable<T> Where(Expression<Func<T, bool>> expression);

        /// <summary>
        /// 条件筛选。
        /// 根据布尔值决定是否应用筛选条件。
        /// </summary>
        /// <param name="isWhere">是否应用筛选</param>
        /// <param name="expression">Lambda表达式筛选条件</param>
        /// <returns>链式调用接口</returns>
        IK3Queryable<T> WhereIF(bool isWhere, Expression<Func<T, bool>> expression);

        /// <summary>
        /// 添加排序规则。
        /// </summary>
        /// <param name="expression">排序字段表达式</param>
        /// <param name="orders">排序类型数组</param>
        /// <returns>链式调用接口</returns>
        IK3Queryable<T> OrderBy(Expression<Func<T, object>> expression, OrderType[]? orders = default);

        /// <summary>
        /// 跳过指定行数。
        /// </summary>
        /// <param name="count">跳过的行数</param>
        /// <returns>链式调用接口</returns>
        IK3Queryable<T> Skip(int count);

        /// <summary>
        /// 取指定行数。
        /// </summary>
        /// <param name="count">取的行数</param>
        /// <returns>链式调用接口</returns>
        IK3Queryable<T> Take(int count);

        /// <summary>
        /// 配置缓存。
        /// </summary>
        /// <param name="cacheDurationInSeconds">缓存时长（秒）</param>
        IK3Queryable<T> WithCache(int cacheDurationInSeconds = int.MaxValue);
        /// <summary>
        /// 配置缓存
        /// </summary>
        /// <param name="cacheKey">自定义缓存键</param>
        /// <param name="cacheDurationInSeconds">缓存 秒</param>
        /// <returns></returns>
        IK3Queryable<T> WithCache(string cacheKey, int cacheDurationInSeconds = int.MaxValue);
        /// <summary>
        /// 返回第一条元数据
        /// </summary>
        /// <returns></returns>
        Task<T?> FirstAsync(CancellationToken cancellation = default);
        /// <summary>
        /// 返回数据(同步)
        /// </summary>
        List<T>? ToList();
        /// <summary>
        /// 返回数据(异步)
        /// </summary>
        Task<List<T>?> ToListAsync(CancellationToken cancellation = default);
        /// <summary>
        /// 查询表单<typeparamref name="T"/>按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, CancellationToken cancellation = default);

        /// <summary>
        /// 按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="totalNumber">返回总条数</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, Refasync<int> totalNumber, CancellationToken cancellation = default);
        /// <summary>
        /// 按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="countField">自定义统计条数字段</param>
        /// <param name="totalNumber">返回总条数</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, string countField, Refasync<int> totalNumber, CancellationToken cancellation = default);
        /// <summary>
        /// 按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="selector">自定义统计条数字段</param>
        /// <param name="totalNumber">返回总条数</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, Expression<Func<T, object>> selector, Refasync<int> totalNumber, CancellationToken cancellation = default);
        /// <summary>
        /// 按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="totalNumber">返回总条数</param>
        /// <param name="totalPage">返回总页数</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, Refasync<int> totalNumber, Refasync<int> totalPage, CancellationToken cancellation = default);
        /// <summary>
        /// 返回记录条数
        /// </summary>
        /// <returns></returns>
        Task<int> CountAsync(CancellationToken cancellation = default);
        /// <summary>
        /// 返回记录条数
        /// </summary>
        /// <param name="countField">计数字段</param>
        Task<int> CountAsync(string countField, CancellationToken cancellation = default);
        /// <summary>
        /// 返回记录条数
        /// </summary>
        /// <param name="selector">计数字段</param>
        /// <returns></returns>
        Task<int> CountAsync(Expression<Func<T, object>> selector, CancellationToken cancellation = default);
        /// <summary>
        /// 汇总
        /// </summary>
        /// <param name="sumFiled">汇总字段</param>
        /// <returns></returns>
        Task<Dictionary<string, decimal>?> SumAsync(CancellationToken cancellation = default, params string[] sumFiled);
        Task<Dictionary<string, decimal>?> SumAsync(params string[] sumFiled);
        /// <summary>
        /// 汇总
        /// </summary>
        /// <param name="selector">汇总字段</param>
        /// <returns></returns>
        Task<Dictionary<string, decimal>?> SumAsync(Expression<Func<T, object>> selector, CancellationToken cancellation = default);
        IK3Queryable<T> Clone();
        /// <summary>
        /// 输出<typeparamref name="TResult"/>字段
        /// <code>需要服务端安装2023年4月以后补丁,支持json单据查询，
        /// 如用t=>t.FQty 那么TResult类型为double 服务端json为[{FQty:123.00},{FQty:456.00}]反序列后不能识别
        /// 所以统一使用匿名类型，如：t=>new {t.FQty}</code>
        /// </summary>
        IK3Queryable<TResult> Select<TResult>(Expression<Func<T, TResult>> selector) where TResult : class;
        /// <summary>
        /// 返回单据查询Json<br/>不返回实际数据
        /// </summary>
        string ToJson();
        /// <summary>
        /// 返回单据查询Json使用<br/>不返回实际数据
        /// </summary>
        IK3Queryable<T> Count(Expression<Func<T, object>> selector);
        /// <summary>
        /// 返回单据查询Json使用<br/>不返回实际数据
        /// </summary>
        IK3Queryable<T> Sum(Expression<Func<T, object>> selector);
    }

    /// <summary>
    /// IK3Queryable扩展方法（功能增强）
    /// </summary>
    public static class K3QueryableExtensions
    {
        /// <summary>
        /// 添加In筛选条件（字段值在集合中）
        /// 例：query.WhereIn(x => x.FStatus, new[] { "A", "B", "C" })
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="TValue">字段值类型</typeparam>
        /// <param name="queryable">查询对象</param>
        /// <param name="selector">字段选择器</param>
        /// <param name="values">值集合</param>
        /// <returns>查询对象</returns>
        public static IK3Queryable<T> WhereIn<T, TValue>(
            this IK3Queryable<T> queryable,
            Expression<Func<T, TValue>> selector,
            IEnumerable<TValue> values) where T : class
        {
            if (values == null || !values.Any())
            {
                return queryable;
            }

            // 获取字段名
            string fieldName = GetMemberName(selector);
            
            // 创建In表达式
            ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
            MemberExpression member = Expression.Property(parameter, fieldName);
            ConstantExpression constant = Expression.Constant(values);
            
            MethodInfo containsMethod = typeof(Enumerable).GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
                .Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(TValue));
            
            MethodCallExpression containsCall = Expression.Call(null, containsMethod, constant, member);
            Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(containsCall, parameter);
            
            return queryable.Where(lambda);
        }

        /// <summary>
        /// 添加NotIn筛选条件（字段值不在集合中）
        /// 例：query.WhereNotIn(x => x.FStatus, new[] { "X", "Y", "Z" })
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="TValue">字段值类型</typeparam>
        /// <param name="queryable">查询对象</param>
        /// <param name="selector">字段选择器</param>
        /// <param name="values">值集合</param>
        /// <returns>查询对象</returns>
        public static IK3Queryable<T> WhereNotIn<T, TValue>(
            this IK3Queryable<T> queryable,
            Expression<Func<T, TValue>> selector,
            IEnumerable<TValue> values) where T : class
        {
            if (values == null || !values.Any())
            {
                return queryable;
            }

            // 获取字段名
            string fieldName = GetMemberName(selector);
            
            // 创建NotIn表达式
            ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
            MemberExpression member = Expression.Property(parameter, fieldName);
            ConstantExpression constant = Expression.Constant(values);
            
            MethodInfo containsMethod = typeof(Enumerable).GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
                .Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(TValue));
            
            MethodCallExpression containsCall = Expression.Call(null, containsMethod, constant, member);
            UnaryExpression notContains = Expression.Not(containsCall);
            Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(notContains, parameter);
            
            return queryable.Where(lambda);
        }

        /// <summary>
        /// 获取表达式中的成员名称
        /// </summary>
        private static string GetMemberName<T, TValue>(Expression<Func<T, TValue>> selector)
        {
            if (selector.Body is MemberExpression memberExpression)
            {
                return memberExpression.Member.Name;
            }
            else if (selector.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression operandMember)
            {
                return operandMember.Member.Name;
            }
            
            throw new ArgumentException("表达式必须是成员访问表达式，例如：x => x.PropertyName", nameof(selector));
        }
    }
}
